﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace MyLib.Web {
	/// <summary>
	/// 
	/// </summary>
	internal class CodeProvider : FileContextProvider {
		/// <summary>
		/// 
		/// </summary>
		private const string CONST_CODE_FILE_NAME = @"ConstSysCode.xml";

		/// <summary>
		/// 
		/// </summary>
		private string m_codeFileName;

		/// <summary>
		/// 
		/// </summary>
		private string m_cacheKey;

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		internal DataTable LoadDataTable() {
			DataTable dataTable = null;

			if (CacheProvider != null) {
				dataTable = CacheProvider[m_cacheKey] as DataTable;
			}

			if (dataTable == null) {
				dataTable = LoadDataTableFromFile(m_codeFileName);

				if (CacheProvider != null) {
					CacheProvider.Add(m_cacheKey, dataTable, m_codeFileName);
				}
			}

			return dataTable;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="categoryId"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static string GetCodeValueFromKey(this HttpContext context, int categoryId, object key) {
			return GetCodeValueFromKey(context, CONST_CODE_FILE_NAME, categoryId, key);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="codeFileName"></param>
		/// <param name="categoryId"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static string GetCodeValueFromKey(this HttpContext context, string codeFileName, int categoryId, object key) {
			var p = new CodeProvider(context.Request.MapPath("~/"), codeFileName);

			var exp = string.Format("cat_id = {0} and [value] = '{1}'", categoryId, key);
			var rows = LoadDataTable(context, cacheKey, codeFileName).Select(exp);

			if (rows != null && rows.Length != 0) {
				return rows[0].GetString(2); // text.
			} else {
				return string.Empty;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="categoryId"></param>
		/// <returns></returns>
		public static IEnumerable<Tuple<string, string, string>> GetCodeValuesFromCategory(this HttpContext context, int categoryId) {
			return GetCodeValuesFromCategory(context, CONST_CODE_FILE_NAME, categoryId);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="codeFileName"></param>
		/// <param name="categoryId"></param>
		/// <returns></returns>
		public static IEnumerable<Tuple<string, string, string>> GetCodeValuesFromCategory(this HttpContext context, string codeFileName, int categoryId) {
			var cacheKey = GetCacheKeyByCodeFile(codeFileName);

			var exp = string.Format("cat_id = {0}", categoryId);
			return LoadDataTable(context, cacheKey, codeFileName).Select(exp)
				.Select(_ =>
					new Tuple<string, string, string>(_.GetString(1), _.GetString(2), _.GetString(3)));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="codeFileName"></param>
		/// <returns></returns>
		private DataTable LoadDataTableFromFile(string codeFileName) {
			var dt = new DataTable();
			dt.Columns.Add("cat_id", typeof(int));
			dt.Columns.Add("value", typeof(string));
			dt.Columns.Add("text", typeof(string));
			dt.Columns.Add("parent_value", typeof(string));

			var doc = XElement.Load(System.IO.Path.Combine(BasePath, codeFileName));
			foreach (var catElement in doc.Elements("category")) {
				var catId = Convert.ToInt32(catElement.Attribute("id").Value);
				foreach (var codeElement in catElement.Elements("code")) {
					var row = dt.NewRow();

					row[0] = catId;
					row[1] = codeElement.Attribute("value").Value;
					row[2] = codeElement.Attribute("text").Value;
					var pvAttr = codeElement.Attribute("parent");
					if (pvAttr != null) {
						row[3] = pvAttr.Value;
					} else {
						row[3] = DBNull.Value;
					}

					dt.Rows.Add(row);
				}
			}

			dt.AcceptChanges();

			return dt;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="basePath"></param>
		public CodeProvider(string basePath)
			: this(basePath, CONST_CODE_FILE_NAME) {
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="basePath"></param>
		/// <param name="codeFileName"></param>
		public CodeProvider(string basePath, string codeFileName)
			: this(basePath, codeFileName, null) {
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="basePath"></param>
		/// <param name="codeFileName"></param>
		/// <param name="cacheProvider"></param>
		public CodeProvider(string basePath, string codeFileName, ICacheProvider cacheProvider)
			: base(basePath, cacheProvider) {
			System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(codeFileName));

			m_codeFileName = System.IO.Path.Combine(basePath, codeFileName);
			m_cacheKey = GetCacheKeyByFileName(codeFileName);
		}
	} // end of DataTableCache.
}
